package com.xu.cloud.common.util;

import com.xu.cloud.common.enums.IEnum;
import com.xu.cloud.common.exception.ErrorCodeEnum;
import com.xu.cloud.common.exception.XuCloudException;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Objects;

/**
 * 异常工具类
 *
 * @author xuguan
 * @since 2024/12/16
 */
public class ExceptionUtil {

    public static RuntimeException wrapRuntimeException(Throwable throwable) {
        return new RuntimeException(throwable);
    }

    public static XuCloudException wrapXuCloudException(Throwable throwable) {
        return wrapXuCloudException(ErrorCodeEnum.INTERNAL_SERVER_ERROR.getCode(),
                ErrorCodeEnum.INTERNAL_SERVER_ERROR.getMessage(),
                throwable);
    }

    public static XuCloudException wrapXuCloudException(IEnum<?> errorCodeEnum, Throwable throwable) {
        return wrapXuCloudException(errorCodeEnum.getCode(),
                errorCodeEnum.getMessage(),
                throwable);
    }

    public static XuCloudException wrapXuCloudException(String code, String message, Throwable throwable) {
        if (throwable instanceof XuCloudException) {
            return (XuCloudException) throwable;
        }
        return new XuCloudException(code, message, throwable);
    }

    public static Throwable unwrapThrowable(Throwable original) {
        Throwable rootCause = original;
        Throwable cause = getCause(original);
        while (Objects.nonNull(cause) && !Objects.equals(rootCause, cause)) {
            rootCause = cause;
            cause = getCause(rootCause);
        }
        return rootCause;
    }

    private static Throwable getCause(Throwable throwable) {
        Throwable cause;
        if (throwable instanceof InvocationTargetException) {
            cause = ((InvocationTargetException) throwable).getTargetException();
        } else if (throwable instanceof UndeclaredThrowableException) {
            cause = ((UndeclaredThrowableException) throwable).getUndeclaredThrowable();
        } else {
            cause = throwable.getCause();
        }
        return cause;
    }

    @SuppressWarnings("ThrowablePrintedToSystemOut")
    public static void main(String[] args) {
        final InvocationTargetException original = new InvocationTargetException(
                wrapXuCloudException(
                        wrapRuntimeException(
                                new NullPointerException("NPE"))));

        // java.lang.NullPointerException: NPE
        System.out.println(unwrapThrowable(original));
    }
}